using System;
using EnvDTE;

namespace NDocBuilder
{
	/// <summary>
	/// This is the main class that will handle the documentation build.
	/// </summary>
	/// <remarks>
	/// The <see cref="Builder"/> class is used to keep track of the <see cref="Configuration">current configuration</see>, the <see cref="ApplicationObject">current application environment</see> and is the owner of the <see cref="OutputPane">text pane</see> that is used for output.<br/><br/>
	/// When the add-in is <see cref="Connect.Exec">executed</see> the <see cref="Connect"/> class will create an instance of <see cref="Builder"/>. 
	/// </remarks>
	/// <example>
	/// The <see cref="Connect"/> class, which implements the plugin interface, will construct a <see cref="Builder"/> instance and provide it the current <see cref="_DTE">application environment object</see>.
	/// <code>
	///	Builder b = new Builder(applicationObject);
	/// b.Build();
	/// </code>
	/// <seealso cref="Connect"/>
	/// <seealso cref="Connect.Exec"/>
	/// <seealso cref="Build"/>
	/// </example>
	public class Builder
	{
		#region Construction

		/// <summary>
		/// The constructor for the Builder class
		/// </summary>
		/// <param name="applicationObject">The current DTE environment</param>
		public Builder(_DTE applicationObject)
		{
			g_Current = this;
			m_ApplicationObject = applicationObject;
		}

		#endregion

		#region Properties

		private static Builder g_Current;
		/// <summary>
		/// The current builder instance
		/// </summary>
		public static Builder Current
		{
			get{return g_Current;}
		}

		private NDocBuilderConfig m_Configuration	= new NDocBuilderConfig();
		/// <summary>
		/// The configuration of NDocBuilder
		/// <seealso cref="NDocBuilderConfig"/>
		/// </summary>
		public NDocBuilderConfig Configuration
		{
			get{return m_Configuration;}
		}

		private _DTE m_ApplicationObject;
		/// <summary>
		/// Get the current VS Application Object
		/// </summary>
		public _DTE ApplicationObject
		{
			get{return m_ApplicationObject;}
		}

		private OutputWindowPane m_OutputPane;
		/// <summary>
		/// The pane we use for text output
		/// </summary>
		public OutputWindowPane OutputPane
		{
			get
			{
				if(m_OutputPane == null)
				{
					Window win =  ApplicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
					OutputWindow ow = (OutputWindow)win.Object;

					m_OutputPane = ow.OutputWindowPanes.Add("NDoc Output");
				}

				return m_OutputPane;
			}
		}

		#endregion

		/// <summary>
		/// This will start the building procedure for all selected projects
		/// </summary>
		/// <remarks>
		/// The builder instance will load the <see cref="NDocBuilderConfig">configuration</see> and launch a documentation <see cref="NDocProject.Build">build</see> for every selected project.
		/// </remarks>
		public void Build()
		{
			try
			{
				// Activate and clear our own text pane (if the text pane doesn't exists it will be created)

	            OutputPane.Activate();
				OutputPane.Clear();
				OutputPane.OutputString(System.Reflection.Assembly.GetExecutingAssembly().FullName + "\n");
				
				// Load the settings from NDocBuilder.Config.Xml

				Configuration.Load();

				// Construct a NDocProject instance for every selected project and 
				// start a build process for that project.

				Array ActiveSolutionProjects = (Array)ApplicationObject.ActiveSolutionProjects;

				if(ActiveSolutionProjects.Length > 0)
				{
					for(int i = 0; i < ActiveSolutionProjects.Length; i++)
					{
						NDocProject proj = new NDocProject((Project)ActiveSolutionProjects.GetValue(i));
						proj.Build();
					}
				}
				else
				{
					OutputPane.OutputString("No projects selected.");
				}
			}
			catch(Exception ex)
			{
				OutputPane.OutputString("Oh dear: \"" + ex.ToString() + "\"\n");
			}
		}

		/// <summary>
		/// Converts an absolute path to a relative one.
		/// </summary>
		/// <param name="strBaseFolder">A string containing the base folder</param>
		/// <param name="strAbsolutePath">A string containing the path to convert</param>
		/// <returns>A string containing a relative path</returns>
		public string CreateRelativePath(string strBaseFolder, string strAbsolutePath)
		{
			// Make sure we always end with a backslash at the end of our base folder.
			strBaseFolder = strBaseFolder.TrimEnd("\\".ToCharArray()) + "\\";

			Uri uriBase = new Uri(strBaseFolder);
			Uri uriAbsolute = new Uri(strAbsolutePath);

			return uriBase.MakeRelative(uriAbsolute);
		}
	}
}
